using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Xml.Serialization;
using System.Windows.Forms;

namespace WOWEquipOptimizer
{
    /// <summary>
    /// main window
    /// </summary>
    public partial class MainWindow : Form
    {
        private Optimizer m_Optimizer;
        private OptimizerManager m_OptimizerManager;
        private delegate void LogInsertDelegate(int index,object input);
        private delegate void UpdateValues(float value);
        private bool[] m_Locks = new bool[Character.SlotCount];
        private bool m_Running = false;
        private bool m_Lock = false;
        private Thread m_OptimizerThread;
        private BuffsDialog m_Buffs;
        private FilterItemsDialog m_FID;
        private SplitterPanel m_ControlsPanel;
        private BlackWhitelistDialog m_BWD = new BlackWhitelistDialog();
        private ConditionsDialog m_CD = new ConditionsDialog();
        private int m_ControlsPanelColumns = 0;

        public Optimizer Optimizer
        {
            get { return m_Optimizer; }
            set { m_Optimizer = value; }
        }
        public MainWindow()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
            this.toolTipMW.OwnerDraw = true;
            this.toolTipMW.Popup += new PopupEventHandler(toolTipMW_Popup);
            this.toolTipMW.Draw += new DrawToolTipEventHandler(toolTipMW_Draw);
            List<float> m_Values = new List<float>();
            this.GraphControl.Values = m_Values;
            m_FID = new FilterItemsDialog();
            m_FID.MaxItemLevel = Item.MaxItemLevel;
            m_FID.MinItemLevel = 0;
            m_FID.setDungeons(Item.AllAreas);
            m_FID.setSources();
            m_ControlsPanel = splitPanel1Container.Panel2;
            SetupBoxes();
            for (int i = 0; i < m_Locks.Length; i++)
            {
                m_Locks[i] = false;
            }

        }
        private void UpdateSet()
        {
            this.Invoke(new MethodInvoker(StopThread));
        }
        private void toolTipMW_Popup(object sender, PopupEventArgs e)
        {
            ComboBox cbox = (ComboBox)e.AssociatedControl;
            Item item = (Item)cbox.SelectedItem;
            if (item == null) throw new Exception("This should never happen");
            using (Font f = new Font("Tahoma", 9))
            {
                e.ToolTipSize = new Size(Math.Max(TextRenderer.MeasureText("Name: " + item.Name, f).Width, 125), Math.Max(TextRenderer.MeasureText(item.Name, f).Height, 150));
            }
        }
        private void toolTipMW_Draw(System.Object sender, System.Windows.Forms.DrawToolTipEventArgs e)
        {
            ComboBox cbox = (ComboBox)e.AssociatedControl;
            Item item = (Item)cbox.SelectedItem;
            if (item == null) return;
            // Draw the standard background.
            e.Graphics.FillRectangle(Brushes.WhiteSmoke, new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1));
            e.Graphics.DrawRectangle(new Pen(Brushes.Black, 1f), new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1));
            using (StringFormat sf = new StringFormat())
            {
                using (Font f = new Font("Tahoma", 9))
                {
                    int fontheight = TextRenderer.MeasureText(item.Name, f).Height;
                    int distance = fontheight / 2;
                    int currenty = 0;
                    e.Graphics.DrawString("Name: " + item.Name, f, Brushes.Black, 0, currenty);
                    currenty += fontheight + distance;
                    e.Graphics.DrawString("Quality: " + item.Quality, f, Brushes.Black, 0, currenty);
                    currenty += fontheight + distance;
                    e.Graphics.DrawString("ID: " + item.Id, f, Brushes.Black, 0, currenty);
                    currenty += fontheight + distance;
                    e.Graphics.DrawString("Ilvl: " + item.Level, f, Brushes.Black, 0, currenty);
                    currenty += fontheight + distance;
                    for (int i = 0; i < item.Attributes.Count; i++)
                    {
                        e.Graphics.DrawString(item.Attributes[i].Type + ": " + item.Attributes[i].Value.ToString("N2"), f, Brushes.Black, 0, currenty);
                        currenty += fontheight + distance;
                    }
                }
            }
        }
        private void UpdateGraphics(float value)
        {
            try
            {
                if (value < 0) return;
                UpdateValues uv = new UpdateValues(GraphControl.Values.Add);
                this.Invoke(uv, new object[] { value });
                MethodInvoker mi = new MethodInvoker(GraphControl.Invalidate);
                this.Invoke(mi);
            }
            catch (Exception)
            {
            }

        }
        /// <summary>
        /// add different classes to our drop down menu
        /// </summary>
        public void SetupClassBox()
        {
            Panel11ClassBox.SelectedIndexChanged += new EventHandler(Panel11ClassBox_SelectedIndexChanged);
            Panel11BuildBox.SelectedIndexChanged += new EventHandler(Panel11BuildBox_SelectedIndexChanged);
            foreach (string classname in Program.ClassBuildDictionary.Keys)
            {
                Panel11ClassBox.Items.Add(classname);
            }
            Panel11ClassBox.SelectedIndex = 0;
        }
        /// <summary>
        /// fill drop down comboxes with useful values
        /// </summary>
        public void FillBoxes()
        {
            m_Lock = true;
            string[] slots = Enum.GetNames(typeof(SlotName));
            this.SuspendLayout();
            for (int i = 0; i < slots.Length-1; i++)
            {
                ComboBox myCombo = (ComboBox) m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 1];
                myCombo.Items.Clear();
                myCombo.Items.AddRange(m_Optimizer.Items[i].ToArray());
                myCombo.SelectedItem = Item.getPlaceholderItem(i);
                for (int k = 0; k < 3; k++)
                {
                    ComboBox myGem = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + k + 3];
                    myGem.Items.Clear();
                    myGem.Items.AddRange(m_Optimizer.Items[m_Optimizer.Items.Length - 1].ToArray());
                    myGem.SelectedItem = Gem.None;
                }
                ComboBox myEnchant = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 7];
                myEnchant.Items.Clear();
                myEnchant.Items.AddRange(Enchant.Enchants[i].ToArray());
                myEnchant.SelectedItem = Enchant.None;
                CheckBox cbox = (CheckBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 8];
                cbox.Checked = false;
            }
            this.ResumeLayout();
            m_Lock = false;
        }
        /// <summary>
        /// initialize comboboxes and stuff
        /// </summary>
        public void SetupBoxes()
        {
            m_Lock = true;
            string[] slots = Enum.GetNames(typeof(SlotName));
            this.SuspendLayout();
            Array.Resize<string>(ref slots, slots.Length - 1);
            m_ControlsPanelColumns = 9;
            int colums = m_ControlsPanel.Width / m_ControlsPanelColumns;
            int rows = m_ControlsPanel.Height / slots.Length;
            int maxwidth = 0;
            for (int i = 0; i < slots.Length; i++)
            {
                Font f = this.Font;
                int width = TextRenderer.MeasureText(slots[i], f).Width;
                if (width > maxwidth)
                {
                    maxwidth = width;
                }
            }
            for (int i = 0; i < slots.Length; i++)
            {
                Label mylabel = new Label();
                mylabel.Name = "Label" + slots[i];
                mylabel.Text = slots[i] + ":";
                mylabel.AutoSize = true;
                mylabel.Anchor = AnchorStyles.Left;
                mylabel.TextAlign = ContentAlignment.MiddleLeft;
                mylabel.AutoSize = true;
                mylabel.Location = new Point(0, rows / 2 + i * rows);
                m_ControlsPanel.Controls.Add(mylabel);
                ComboBox myCombo = new ComboBox();
                myCombo.Name = "Cbox" + slots[i];
                myCombo.DropDownStyle = ComboBoxStyle.DropDownList;
                myCombo.ValueMember = "Name";
                myCombo.Sorted = true;
                myCombo.Items.Add(Item.getPlaceholderItem(i));
                myCombo.SelectedItem = Item.getPlaceholderItem(i);
                myCombo.Anchor = AnchorStyles.Left;
                myCombo.SelectedIndexChanged += new EventHandler(SlotComboBox_SelectedIndexChanged);
                myCombo.SelectedIndexChanged += new EventHandler(UpdateTV);
                myCombo.Location = new Point(maxwidth + 5, rows / 2 + i * rows);
                m_ControlsPanel.Controls.Add(myCombo);
                toolTipMW.SetToolTip(myCombo, myCombo.Name);
                Label myGemLabel = new Label();
                myGemLabel.Name = "GemLabel" + slots[i];
                myGemLabel.Text = "Gems:";
                myGemLabel.AutoSize = true;
                myGemLabel.Anchor = AnchorStyles.Left;
                myGemLabel.TextAlign = ContentAlignment.MiddleLeft;
                myGemLabel.AutoSize = true;
                myGemLabel.Location = new Point(myCombo.Right + 5, rows / 2 + i * rows);
                m_ControlsPanel.Controls.Add(myGemLabel);
                int gemright = myGemLabel.Right + 5;
                for (int k = 0; k < 3; k++)
                {
                    ComboBox myGem = new ComboBox();
                    myGem.Name = "CboxGem" + slots[i] + k;
                    myGem.DropDownStyle = ComboBoxStyle.DropDownList;
                    myGem.ValueMember = "Name";
                    myGem.Sorted = true;
                    myGem.Items.Add(Gem.None);
                    myGem.SelectedItem = Gem.None;
                    myGem.SelectedIndexChanged += new EventHandler(UpdateTV);
                    myGem.Enabled = false;
                    myGem.Anchor = AnchorStyles.Left;
                    myGem.Location = new Point(gemright, rows / 2 + i * rows);
                    m_ControlsPanel.Controls.Add(myGem);
                    toolTipMW.SetToolTip(myGem, myGem.Name);
                    gemright += myGem.Size.Width + 5;
                }
                Label myEnchantLabel = new Label();
                myEnchantLabel.Name = "EnchantLabel" + slots[i];
                myEnchantLabel.Text = "Enchant:";
                myEnchantLabel.AutoSize = true;
                myEnchantLabel.Anchor = AnchorStyles.Left;
                myEnchantLabel.TextAlign = ContentAlignment.MiddleLeft;
                myEnchantLabel.AutoSize = true;
                myEnchantLabel.Location = new Point(gemright + 5, rows / 2 + i * rows);
                m_ControlsPanel.Controls.Add(myEnchantLabel);
                ComboBox myEnchant = new ComboBox();
                myEnchant.Name = "CboxEnchant" + slots[i];
                myEnchant.DropDownStyle = ComboBoxStyle.DropDownList;
                myEnchant.ValueMember = "Name";
                myEnchant.Enabled = false;
                myEnchant.Items.Add(Enchant.None);
                myEnchant.SelectedItem = Enchant.None;
                myEnchant.SelectedIndexChanged += new EventHandler(UpdateTV);
                myEnchant.Anchor = AnchorStyles.Left;
                myEnchant.Location = new Point(myEnchantLabel.Right + 5, rows / 2 + i * rows);
                m_ControlsPanel.Controls.Add(myEnchant);
                toolTipMW.SetToolTip(myEnchant, myEnchant.Name);
                CheckBox myCheckbox = new CheckBox();
                myCheckbox.Name = "LockCheck" + i;
                myCheckbox.Checked = false;
                myCheckbox.Text = "Locked";
                myCheckbox.CheckedChanged += new EventHandler(LockChanged);
                myCheckbox.Anchor = AnchorStyles.Left;
                myCheckbox.Location = new Point(myEnchant.Right + 5, rows / 2 + i * rows);
                m_ControlsPanel.Controls.Add(myCheckbox);
            }
            this.ResumeLayout();
            m_Lock = false;
        }
        private void Panel11BuildBox_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            SetupOptimization(true);
        }
        /// <summary>
        /// setup optimization, either full or partial
        /// </summary>
        /// <param name="full"></param>
        private void SetupOptimization(bool full)
        {
            if (full)
            {
                string classname = (string)Panel11ClassBox.SelectedItem;
                string buildname = (string)Panel11BuildBox.SelectedItem;
                Assembly myAsm = Assembly.GetExecutingAssembly();
                Character character = (Character)myAsm.CreateInstance(myAsm.GetName().Name + "." + classname + "." + buildname);
                character.Conditions = m_CD.Conditions;
                foreach (AttributeName attrn in m_CD.Conditions.Keys)
                {
                    if (!character.GoodAttributes.Contains(attrn))
                    {
                        character.GoodAttributes.Add(attrn);
                    }
                }
                if (!character.GoodAttributes.Contains(AttributeName.Stamina))
                {
                    character.GoodAttributes.Add(AttributeName.Stamina);
                }
                character.ItemWhitelist.Clear();
                character.ItemWhitelist.AddRange(m_BWD.ItemWhitelist);
                character.ItemBlacklist.Clear();
                character.ItemBlacklist.AddRange(m_BWD.ItemBlacklist);
                List<Item> items = character.filterEquip(Database.Items);
                if (character == null) return;
                m_Locks = new bool[Character.SlotCount];
                m_OptimizerManager = new OptimizerManager(items, character, m_Locks, UpdateGraphics);
                m_Optimizer = m_OptimizerManager.Optimizer;
                FillBoxes();
                GraphControl.Reset();
                Panel11TVBox.Text = "";
                Panel11AttrBox.Items.Clear();
                m_Buffs = new BuffsDialog();
                foreach (Buff buff in m_Optimizer.Target.Buffs)
                {
                    m_Buffs.addBuff(buff);
                }
                HandleButtons(true);
                m_Optimizer.Target.evaluateBuffs(m_Buffs.getBuffs());
                Panel11StartOptimizationButton.Enabled = true;
            }
            else
            {                
                m_Optimizer = m_OptimizerManager.Optimizer;
                m_Optimizer.UpdateGraphics = UpdateGraphics;
                HandleButtons(true);
                m_Optimizer.Target.evaluateBuffs(m_Buffs.getBuffs());
                Panel11StartOptimizationButton.Enabled = true;
            }
        }
        /// <summary>
        /// update necessary values if the locks are changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LockChanged(object sender, System.EventArgs e)
        {
            for (int i = 0; i < m_Locks.Length; i++)
            {
                CheckBox cbox = (CheckBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 8];
                m_Locks[i] = cbox.Checked;
            }
        }
        /// <summary>
        /// update target value
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateTV(object sender, System.EventArgs e)
        {
            if (m_Lock) return;
            Item[] items = getItems();
            ulong hashold = Item.GetHashCode(items);
            if (m_Optimizer == null) return;
            GraphControl.Reset();
            Character target = m_Optimizer.Target;
            lock (target)
            {
                target.Slots = (Item[]) items.Clone();
                target.evaluateEquip();
                ulong hash = Item.GetHashCode(target.Slots);
                float tv = target.evaluateTF();
                m_OptimizerManager.MaxTV = tv;
                Character.UseSpecials = true;
                target.evaluateEquip();
                Character.UseSpecials = true;
                Panel11TVLabel.Text = target.targetValue() + ":";
                Panel11TVBox.Text = tv.ToString("N");
                Panel11AttrBox.SuspendLayout();
                Panel11AttrBox.Items.Clear();
                List<string> attrs = new List<string>();
                attrs.AddRange(target.getAttributes());
                foreach (AttributeName key in target.Conditions.Keys)
                {
                    string keystring = key.ToString();
                    if (!attrs.Contains(keystring))
                    {
                        attrs.Add(keystring);
                    }
                }
                int start = target.getAttributesStart();
                for (int i = start; i < attrs.Count; i++)
                {
                    string text = string.Empty;
                    AttributeName attrname = (AttributeName)Enum.Parse(typeof(AttributeName), attrs[i], true);
                    switch (attrs[i])
                    {
                        case "WeaponSkillRating":
                            text = attrs[i].Replace("Rating","") +": " + (target.getData(attrname) / Character.WeaponSkillRating).ToString("N2");
                            break;
                        case "DefenseSkillRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.DefenseSkillRating).ToString("N2");
                            break;
                        case "HitRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.HitRating).ToString("N2") + "%";
                            break;
                        case "CritRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.CritRating).ToString("N2") + "%";
                            break;
                        case "HasteRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.HasteRating).ToString("N2") + "%";
                            break;
                        case "HitSpellRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.HitSpellRating).ToString("N2") + "%";
                            break;
                        case "CritSpellRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.CritSpellRating).ToString("N2") + "%";
                            break;
                        case "HasteSpellRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.HasteSpellRating).ToString("N2") + "%";
                            break;
                        case "DodgeRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.DodgeRating).ToString("N2") + "%";
                            break;
                        case "ParryRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.ParryRating).ToString("N2") + "%";
                            break;
                        case "BlockRating":
                            text = attrs[i].Replace("Rating", "") + ": " + (target.getData(attrname) / Character.BlockRating).ToString("N2") + "%";
                            break;
                        default:
                            text = attrs[i] + ": " + target.getData(attrname).ToString("N2");
                            break;
                    }
                    Panel11AttrBox.Items.Add(text);
                }
                Panel11AttrBox.ResumeLayout();
            }
        }
        private void Panel11ClassBox_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            Panel11BuildBox.SuspendLayout();
            Panel11BuildBox.Items.Clear();
            Panel11BuildBox.Items.AddRange(Program.ClassBuildDictionary[(string)Panel11ClassBox.SelectedItem].ToArray());
            Panel11BuildBox.ResumeLayout();
        }
        /// <summary>
        /// complicated function, includes cases for dual wield weapons -> shield, twohand -> shield etc.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SlotComboBox_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            this.SuspendLayout();
            lock (m_ControlsPanel)
            {
                ComboBox cbox = (ComboBox)sender;
                Item item = (Item)cbox.SelectedItem;
                int mhindex = 127;
                int ohindex = 136;
                int index = m_ControlsPanel.Controls.IndexOf(cbox);
                for (int k = 0; k < 3; k++)
                {
                    ComboBox gembox = (ComboBox)m_ControlsPanel.Controls[index + k + 2];
                    gembox.Enabled = false;
                    if (item.SocketCount > k)
                    {
                        gembox.Enabled = true;
                        gembox.SelectedItem = Gem.None;
                    }
                }
                ComboBox enchant = (ComboBox)m_ControlsPanel.Controls[index + 6];
                if (enchant.Items.Count > 1 && item.Id != Item.NoneId )
                {
                    enchant.Enabled = true;
                    enchant.SelectedItem = Enchant.None;
                }
                else
                {
                    enchant.Enabled = false;
                    enchant.SelectedItem = Enchant.None;
                }
                if (!(index == 127 || index == 136)) return;
                ComboBox mhcbox = (ComboBox)m_ControlsPanel.Controls[127];
                ComboBox ohcbox = (ComboBox)m_ControlsPanel.Controls[136];
                Item mh = (Item)mhcbox.SelectedItem;
                Item oh = (Item)ohcbox.SelectedItem;
                if (item.GetType() == typeof(Weapon))
                {
                    enchant = (ComboBox)m_ControlsPanel.Controls[mhindex + 6];
                    if ((mh as Weapon) != Weapon.None)
                    {
                        if (enchant.Items.Count == 1)
                        {
                            enchant.Items.Clear();
                            enchant.Items.AddRange(Enchant.Enchants[(int)SlotName.MainHand].ToArray());
                            enchant.SelectedItem = Enchant.None;
                            enchant.Enabled = true;
                        }
                        if ((mh as Weapon).TwoHand)
                        {
                            enchant.Items.Clear();
                            enchant.Items.AddRange(Enchant.TwoHand.ToArray());
                            enchant.SelectedItem = Enchant.None;
                            enchant.Enabled = true;
                            ohcbox.SelectedItem = Weapon.None;

                        }
                    }
                    else if ((mh as Weapon) == Weapon.None)
                    {
                        if (enchant.Items.Count > 1)
                        {
                            enchant.Items.Clear();
                            enchant.Items.Add(Enchant.None);
                            enchant.SelectedItem = Enchant.None;
                            enchant.Enabled = false;
                        }
                    }
                }
                if (item.GetType() == typeof(Weapon))
                {
                    enchant = (ComboBox)m_ControlsPanel.Controls[ohindex + 6];
                    if ((oh as Weapon) != Weapon.None && (!(mh as Weapon).TwoHand))
                    {
                        if (enchant.Items.Count == 1)
                        {
                            enchant.Items.Clear();
                            enchant.Items.AddRange(Enchant.Enchants[(int)SlotName.OffHand].ToArray());
                            enchant.SelectedItem = Enchant.None;
                            enchant.Enabled = true;
                            if ((mh as Weapon).TwoHand)
                            {
                                mhcbox.SelectedItem = Weapon.None;
                            }
                        }
                    }
                    else
                    {
                        if (enchant.Items.Count > 1)
                        {
                            enchant.Items.Clear();
                            enchant.Items.Add(Enchant.None);
                            enchant.SelectedItem = Enchant.None;
                            enchant.Enabled = false;
                        }
                    }
                }
                else if (item.GetType() == typeof(Armor))
                {
                    enchant = (ComboBox)m_ControlsPanel.Controls[ohindex + 6];
                    if ((oh as Armor).Type == ArmorProficiency.Shield)
                    {
                        if (enchant.Items.Count == 1)
                        {
                            enchant.Items.Clear();
                            enchant.Items.AddRange(Enchant.Shield.ToArray());
                            enchant.SelectedItem = Enchant.None;
                            enchant.Enabled = true;
                            if ((mh as Weapon).TwoHand)
                            {
                                mhcbox.SelectedItem = Weapon.None;
                            }
                        }
                    }
                    else
                    {
                        enchant.Items.Clear();
                        enchant.Items.Add(Enchant.None);
                        enchant.SelectedItem = Enchant.None;
                        enchant.Enabled = false;
                    }
                }

            }
            this.ResumeLayout();
        }
        /// <summary>
        /// generic m_Items are loaded from file/url
        /// </summary>
        /// <param name="m_Items"></param>
        private void setGenericItems(GenericItem[] items)
        {
            m_Lock = true;
            for (int i = 0; i < items.Length; i++)
            {
                GenericItem item = items[i];
                ComboBox cbox = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 1];
                cbox.SelectedItem = Item.getPlaceholderItem(i);
                foreach (Item test in cbox.Items)
                {
                    if (test.Id == item.Id)
                    {
                        cbox.SelectedItem = test;
                        break;
                    }
                }
                int[] gems = new int[3];
                gems[0] = item.Gem0Id;
                gems[1] = item.Gem1Id;
                gems[2] = item.Gem2Id;
                for (int m = 0; m < 3; m++)
                {
                    ComboBox cGem = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + m + 3];
                    cGem.SelectedItem = Gem.None;
                    foreach (Gem gem in cGem.Items)
                    {
                        if (gem.Id == gems[m])
                        {
                            cGem.SelectedItem = gem;
                            break;
                        }
                    }
                }
                ComboBox cEnchant = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 7];
                for(int m = 0;m<cEnchant.Items.Count;m++)
                {

                    if ((cEnchant.Items[m] as Enchant).Name == items[i].EnchantName)
                    {
                        cEnchant.SelectedItem = cEnchant.Items[m];
                        break;
                    }
                }
            }
            m_Lock = false;
        }
        /// <summary>
        /// Set Items
        /// </summary>
        /// <param name="m_Items"></param>
        private void setItems(Item[] items)
        {
            m_Lock = true;
            for (int i = 0; i < items.Length; i++)
            {
                Item item = items[i];
                ComboBox cbox = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 1];
                cbox.SelectedItem = Item.getPlaceholderItem(i);
                foreach (Item test in cbox.Items)
                {
                    if (test.Id == item.Id)
                    {
                        cbox.SelectedItem = test;
                        break;
                    }
                }
                for (int m = 0; m < 3; m++)
                {
                    ComboBox cGem = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + m + 3];
                    if (m < item.SocketCount && item.Gems[m] != null)
                    {
                        foreach (Gem gem in cGem.Items)
                        {
                            if (gem.Id == item.Gems[m].Id)
                            {
                                cGem.SelectedItem = gem;
                                break;
                            }
                        }
                    }
                    else cGem.SelectedItem = Gem.None;

                }
                ComboBox cEnchant = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 7];
                for (int m = 0; m < cEnchant.Items.Count; m++)
                {

                    if ((cEnchant.Items[m] as Enchant).Name == item.Enchant.Name)
                    {
                        cEnchant.SelectedItem = cEnchant.Items[m];
                        break;
                    }
                }
            }
            m_Lock = false;
        }
        /// <summary>
        /// get m_Items, obviously returns our selected itemset
        /// </summary>
        /// <returns></returns>
        private Item[] getItems()
        {
            Item[] retval = new Item[Character.SlotCount];
            for (int i = 0; i < retval.Length; i++)
            {
                ComboBox cbox = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 1];
                Item item = (Item)cbox.SelectedItem;
                if (item.SocketCount > 0)
                {
                    item.Gems = new Gem[3];
                    for (int m = 0; m < item.SocketCount; m++)
                    {
                        ComboBox cGem = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + m + 3];
                        item.Gems[m] = (Gem) cGem.SelectedItem;

                    }
                }
                ComboBox enchant = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 1 + 6];
                item.Enchant = (Enchant)enchant.SelectedItem;
                retval[i] = item;
            }
            return retval;
        }
        /// <summary>
        /// get generic m_Items, returns the selected m_Items as generic ones
        /// </summary>
        /// <returns></returns>
        private GenericItem[] getGenericItems()
        {
            GenericItem[] retval = new GenericItem[Character.SlotCount];
            for (int i = 0; i < retval.Length; i++)
            {
                ComboBox cbox = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + 1];
                Item item = (Item)cbox.SelectedItem;
                if (item.SocketCount > 0)
                {
                    item.Gems = new Gem[3];
                    for (int m = 0; m < item.SocketCount; m++)
                    {
                        ComboBox cGem = (ComboBox)m_ControlsPanel.Controls[i * m_ControlsPanelColumns + m + 3];
                        item.Gems[m] = (Gem)cGem.SelectedItem;

                    }
                }
                int[] gems = new int[3];
                for (int m = 0; m < gems.Length; m++)
                {
                    gems[m] = 99999;
                }
                for (int m = 0; m < item.SocketCount; m++)
                {
                    if (item.Gems[m] != null)
                    {
                        gems[m] = item.Gems[m].Id;
                    }
                }
                retval[i].Gem0Id = gems[0];
                retval[i].Gem1Id = gems[1];
                retval[i].Gem2Id = gems[2];
                retval[i].Id = item.Id;
                retval[i].EnchantName = item.Enchant.Name;
            }
            return retval;
        }
        private void MainWindowClosed(object sender, FormClosedEventArgs e)
        {
            Character.SaveLists();
        }
        /// <summary>
        /// button handling for additional forms below
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Panel11LoadProfileButton_Click(object sender, EventArgs e)
        {
            CharParseDialog cpd = new CharParseDialog();
            cpd.ShowDialog();
            ParsedCharacter pc = new ParsedCharacter();
            if (cpd.DialogResult == DialogResult.OK)
            {
                string url = cpd.GetURL();
                if (url.ToLower().Contains(@"http://"))
                {
                    url = url.Replace("/#", "/");
                    url = url.Replace("?#", "");
                    if (url.Length < 20) return;
                    pc = Database.parseCharacter(url);
                }
                else
                {
                    FileStream stream = new FileStream(url, FileMode.Open);
                    XmlSerializer serializer = new XmlSerializer(typeof(ParsedCharacter));
                    try
                    {
                        pc = (ParsedCharacter)serializer.Deserialize(stream);
                    }
                    catch (Exception)
                    {
                    }
                    finally
                    {
                        stream.Close();
                    }
                }
                if (pc.Items == null)
                {
                    MessageBox.Show("Can't parse Characterinfo", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else if (pc.Class == null)
                {
                    MessageBox.Show("Can't parse Characterinfo", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else if (pc.Build == null)
                {
                    MessageBox.Show("Can't evaluate Build, using current Class/Build Information", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    setGenericItems(pc.Items);
                    UpdateTV(null, null);                    
                }
                else
                {
                    Panel11ClassBox.SelectedItem = pc.Class;
                    Panel11BuildBox.SelectedItem = pc.Build;
                    setGenericItems(pc.Items);
                    UpdateTV(null, null);                    
                }
            }
        }
        private void StopThread()
        {
            Panel11StartOptimizationButton.Text = "Start Optimization";
            HandleButtons(true);
            setItems(m_Optimizer.Target.Slots);
            m_Running = false;
            UpdateTV(null, null);
        }
        private void StartThread()
        {
            m_Running = true;
            Panel11StartOptimizationButton.Text = "Abort Optimization";
            HandleButtons(false);

        }
        private void HandleButtons(bool enable)
        {
            Panel11LoadProfileButton.Enabled = enable;
            Panel11BuildBox.Enabled = enable;
            Panel11ClassBox.Enabled = enable;
            Panel11BuffsButton.Enabled = enable;
            Panel11ClipboardButton.Enabled = enable;
            Panel11SaveProfileButton.Enabled = enable;
            Panel11FilterButton.Enabled = enable;
            Panel11BWListButton.Enabled = enable;
            Panel11ConditionsButton.Enabled = enable;
        }
        private void Panel11StartOptimizationButton_Click(object sender, EventArgs e)
        {
            if (!m_Running)
            {
                SetupOptimization(false);
                ThreadStart myStart = new ThreadStart(m_Optimizer.Optimize);
                m_OptimizerThread = new Thread(myStart);
                m_OptimizerThread.IsBackground = true;
                m_Optimizer.Notify = UpdateSet;
                m_OptimizerThread.Start();
                m_Running = true;
                Panel11StartOptimizationButton.Text = "Abort Optimization";
                HandleButtons(false);
            }
            else
            {
                Panel11StartOptimizationButton.Text = "Start Optimization";
                HandleButtons(true);
                m_Running = false;
                m_Optimizer.Abort();
            }
        }

        private void Panel11BuffsButton_Click(object sender, EventArgs e)
        {
            m_Buffs.ShowDialog();
            if (m_Buffs.DialogResult == DialogResult.OK)
            {
                Character.HasBlessingOfKings = m_Buffs.getBoKState();
                m_Optimizer.Target.evaluateBuffs(m_Buffs.getBuffs());
                UpdateTV(null, null);
            }
        }

        private void Panel11ClipboardButton_Click(object sender, EventArgs e)
        {
            string cbtext = "Optimization Result for " + Panel11ClassBox.SelectedItem + "/" + Panel11BuildBox.SelectedItem + "\n\n";
            for(int i = 0;i<m_Optimizer.Target.Slots.Length;i++)
            {
                if (m_Optimizer.Target.Slots[i] != null)
                {
                    cbtext += (SlotName)i + ": " + m_Optimizer.Target.Slots[i].ToString() + "\n";
                }
            }
            cbtext += Panel11TVLabel.Text +" "+ Panel11TVBox.Text+"\n";
            cbtext += "Calculated Attributes:\n";
            for (int i = 0; i < Panel11AttrBox.Items.Count; i++)
            {
                cbtext += Panel11AttrBox.Items[i] + "\n";
            }
            Clipboard.SetText(cbtext);
        }

        private void Panel11SaveProfileButton_Click(object sender, EventArgs e)
        {
            ParsedCharacter pc = new ParsedCharacter();
            pc.Build = (string)Panel11BuildBox.SelectedItem;
            pc.Class = (string) Panel11ClassBox.SelectedItem;
            pc.Items = getGenericItems();
            saveEquipDialog.Filter = "xef files (*.xef)|*.xef|All files (*.*)|*.*";
            saveEquipDialog.FilterIndex = 1;
            saveEquipDialog.RestoreDirectory = true;
            if (saveEquipDialog.ShowDialog() == DialogResult.OK)
            {
                FileStream stream = (FileStream) saveEquipDialog.OpenFile();
                XmlSerializer serialize = new XmlSerializer(typeof(ParsedCharacter));
                serialize.Serialize(stream, pc);
                stream.Close();
            }
        }

        private void Panel11FilterButton_Click(object sender, EventArgs e)
        {
            if (m_FID.ShowDialog() == DialogResult.OK)
            {
                Item.FilterItemLevelAbove = m_FID.MaxItemLevel;
                Item.FilterItemLevelBelow = m_FID.MinItemLevel;
                Item.FilterArea = m_FID.getDungeonFilter();
                Item.FilterSource = m_FID.getSourceFilter();
                Panel11BuildBox_SelectedIndexChanged(null, null);
            }
        }

        private void Panel11BWListButton_Click(object sender, EventArgs e)
        {
            m_BWD.Populate();
            m_BWD.ItemBlacklist = m_OptimizerManager.Target.ItemBlacklist;
            m_BWD.ItemWhitelist = m_OptimizerManager.Target.ItemWhitelist;
            m_BWD.Items = m_OptimizerManager.ItemList;
            if (m_BWD.ShowDialog() == DialogResult.OK)
            {
                Panel11BuildBox_SelectedIndexChanged(null, null);
            }
        }
        private void Panel11ConditionsButton_Click(object sender, EventArgs e)
        {
            if (m_CD.ShowDialog() == DialogResult.OK)
            {
                Panel11BuildBox_SelectedIndexChanged(null, null);
            }
        }
    }
}